﻿using System.Diagnostics.CodeAnalysis;
using OrderMicroService.Domain.Repository;
using OrderMicroService.Infrastructure.Repository.Common;
using OrderMicroService.Types.Types;

namespace OrderMicroService.Infrastructure.Repository
{
    public abstract class DbRepositorySupport<T, ID> : IRepository<T, ID>
         where T : IAggregate<ID>
         where ID : IIdentifier
    {
        // 让 AggregateManager 去维护
        private IAggregateManager<T, ID> aggregateManager;

        public DbRepositorySupport(IAggregateManager<T, ID> aggregateManager)
        {
            this.aggregateManager = aggregateManager;
        }

        #region 这几个方法是继承的子类应该去实现的

        protected abstract void OnInsert(T aggregate);

        protected abstract T OnSelect(ID id);

        protected abstract void OnUpdate(T aggregate, EntityDiff diff);

        protected abstract void OnDelete(T aggregate);

        #endregion 这几个方法是继承的子类应该去实现的

        /// <summary>
        /// Attach 的操作就是让 Aggregate 可以被追踪
        /// </summary>
        /// <param name="aggregate"></param>
        public void Attach([NotNull] T aggregate)
        {
            aggregateManager.Attach(aggregate);
        }

        /// <summary>
        /// Detach 的操作就是让 Aggregate 停止追踪
        /// </summary>
        public void Detach([NotNull] T aggregate)
        {
            aggregateManager.Detach(aggregate);
        }

        /// <summary>
        /// 这里的就是让查询出来的对象能够被追踪。
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T Find([NotNull] ID id)
        {
            T aggregate = OnSelect(id);
            if (aggregate != null)
            {
                //如果自己实现了一个定制查询接口，要记得单独调用 attach。
                Attach(aggregate);
            }
            return aggregate;
        }

        /// <summary>
        /// 删除，停止追踪
        /// </summary>
        /// <param name="aggregate"></param>
        public void Remove([NotNull] T aggregate)
        {
            OnDelete(aggregate);
            Detach(aggregate);
        }

        public void Save([NotNull] T aggregate)
        {
            // 如果没有 ID，直接插入
            if (aggregate.GetId() == null)
            {
                OnInsert(aggregate);
                Attach(aggregate);
                return;
            }
            // 做 Diff
            var diff = aggregateManager.DetectChanges(aggregate);
            if (diff == null)
            {
                return;
            }
            // 调用 UPDATE
            OnUpdate(aggregate, diff);
            // 最终将 DB 带来的变化更新回 AggregateManager
            aggregateManager.Merge(aggregate);
        }
    }
}